/*
 * @Author: ljb
 * @Description: 
 * @Date: 2021-11-09 10:17:01
 * @LastEditTime: 2021-11-09 10:17:01
 * @FilePath: \mvvm\lib\Mvvm.js
 */
import Watcher from './Watcher'

class Vue {
    constructor(options) {
        this.$options = options
        this.$root = document.querySelector(options.el)
        this.$data = options.data()
        this.$methods = options.methods
        this.binding = {}

        this.observe(this.$data)
        this.compile(this.$root)
    }

    observe(data) {
        let _this = this
        let handle = {
            get: function(obj, key, receiver) {
                if (typeof obj[key] == 'object' && obj[key] != null) {
                    return new Proxy(obj, handle)
                }
                return Reflect.get(obj, key)
            },
            set: function(obj, key, value, receiver) {
                console.log(`对象“${obj}的属性“${key}”被改变了，newValue：${value}`)
                
                let ret = Reflect.set(obj, key, value)

                for (let prop in _this.binding) {
                    if (_this.binding[prop].length) {
                        
                        _this.binding[prop].forEach(_watcher => {
                            console.log(_watcher)
                            _watcher.update()
                        })
                    }
                }

                return ret
            }
        }

        this.$data = new Proxy(data, handle)
    }

    pushWatcher(prop, watcher) {
        if (!this.binding[prop]) {
            this.binding[prop] = []
        }
        this.binding[prop].push(watcher)
    }

    compile(root) {
        let _this = this
        for (let i=0; i<root.children.length; i++) {
            let node = root.children[i]
            if (node.children.length) {
                _this.compile(node)
            }

            if (node.hasAttribute('v-bind')) {
                let attr = node.getAttribute('v-bind')
                _this.pushWatcher(attr, new Watcher(
                    'text',
                    node,
                    _this,
                    attr,
                    'innerHTML'
                ))
            }

            if (node.hasAttribute('v-model')) {
                let attr = node.getAttribute('v-model')

                _this.pushWatcher(attr, new Watcher(
                    'value',
                    node,
                    _this,
                    attr,
                    'value'
                ))
                node.addEventListener('input', function() {
                    _this.$data[attr] = node.value
                })
            }

            if (node.hasAttribute('v-click')) {
                let attr = node.getAttribute('v-click')

                node.onclick = function() {
                    return _this.$methods[attr].call(_this.$data)
                }
            }
        }
    }
}

export default Vue